
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/if_packet.h>
#include <netinet/if_ether.h>
#include <netinet/in.h>
#include <netinet/ether.h>
#include "normal_udp.h"

#define ETHTYPE_OFFSET 12
#define DOT1Q_ETHTYPE_OFFSET 16
#define IP_ID_OFFSET 18
#define DST_IP_OFFSET 30
#define PAYLOAD_OFFSET 42
#define IPV4_PACKET 0x0008
#define DOT1Q_FRAME 0x0081
#define DST_IP_FILTER 0xefefef05 // 239.239.239.5 is DST IP we want to read
#define BEST_QUOTE_MSG 1
#define DEPTH_UPDATE_MSG 2

int main(int argc, char **argv)
{
    int sockfd;
    char buf[10240];
    ssize_t n;

    uint16_t prev_ip_id = 0;
    // char output_data[256];

    int size = 0;
    // int result = 0;

    struct ifreq req; // 网络接口地址
    struct sockaddr_ll addr;
    int header_printed = 0;

    if (argc != 2)
    {
        printf("Usage: ./zce-raw-socket ens1f[0:1]\n");
        return 1;
    }

    if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1)
    {
        printf("socket error!\n");
        return 1;
    }
    memcpy(req.ifr_name, argv[1], strlen(argv[1])); // 指定网卡名称
    if (-1 == ioctl(sockfd, SIOCGIFFLAGS, &req))    // 获取网络接口
    {
        perror("ioctl");
        // close(sockfd);
        exit(-1);
    }

    req.ifr_flags |= IFF_PROMISC;
    if (-1 == ioctl(sockfd, SIOCGIFFLAGS, &req)) // 网卡设置混杂模式
    {
        perror("ioctl");
        // close(sockfd);
        exit(-1);
    }

    // 绑定套接字到指定网卡
    memset(&addr, 0, sizeof(addr));
    addr.sll_family = PF_PACKET;
    addr.sll_protocol = htons(ETH_P_ALL);
    addr.sll_ifindex = if_nametoindex(req.ifr_name);
    if (addr.sll_ifindex == 0)
    {
        fprintf(stderr, "Unknown interface: %s\n", req.ifr_name);
        exit(EXIT_FAILURE);
    }
    if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        perror("bind");
        exit(EXIT_FAILURE);
    }

    while (1)
    {
        n = recv(sockfd, buf, sizeof(buf), 0);
        if (n == -1)
        {
            printf("recv error!\n");
            break;
        }
        else if (n == 0)
            continue;
        // 接收数据不包括数据链路帧头
        //        printf("recv %ld\n", n);

        size = n;
        char *packet_buf = (char *)(buf);

        if (size > 64)
        {

            uint16_t *ethtype = (uint16_t *)(packet_buf + ETHTYPE_OFFSET);
            uint16_t *dot1q_ethtype = (uint16_t *)(packet_buf + DOT1Q_ETHTYPE_OFFSET);
            int dot1q_offset = 0;

            if (*ethtype == IPV4_PACKET)
                dot1q_offset = 0;
            else if (*ethtype == DOT1Q_FRAME && *dot1q_ethtype == IPV4_PACKET)
                dot1q_offset = 4;
            else
                continue;

            if (ntohl(*((uint32_t *)(packet_buf + dot1q_offset + DST_IP_OFFSET))) != DST_IP_FILTER)
                continue;

            uint16_t last_ip_id = ntohs(*((uint16_t *)(packet_buf + dot1q_offset + IP_ID_OFFSET)));
            if ((uint16_t)(prev_ip_id + 0x0001) != last_ip_id)
            {
                printf("<WARN> IP_ID sequence number gap previous/latest: %d/%d \n", prev_ip_id, last_ip_id);
            }
            prev_ip_id = last_ip_id;

            st_best_depth_update *best_depth_update = (st_best_depth_update *)(packet_buf + dot1q_offset + PAYLOAD_OFFSET);
            uint16_t decimal = best_depth_update->decimal;

#if 1
            if (!header_printed) {
                printf("合约代码, 时间戳.微秒, 最新价格, 成交量, 持仓量, 总成交额 | 买五档(价格_成交量_委托量), 买四档, 买三档, 买二档, 买一档 | 卖一档, 卖二档, 卖三档, 卖四档, 卖五档\n");
                printf("------------------------------------------------------------------------------------------------------------------------------------\n");
                header_printed = 1;
            }

            printf("%s, %d.%.6d, %.2f, %d, %d, %.2lf | %.2f_%d_%d, %.2f_%d_%d, %.2f_%d_%d, %.2f_%d_%d, %.2f_%d_%d | %.2f_%d_%d, %.2f_%d_%d, %.2f_%d_%d, %.2f_%d_%d, %.2f_%d_%d\n",
                   best_depth_update->contract_id,

                   best_depth_update->update_time,
                   best_depth_update->update_time_usec,

                   (float)best_depth_update->last_price / decimal,
                   best_depth_update->volumn,
                   best_depth_update->open_interest,
                   (double)best_depth_update->turnover / decimal,

                   (float)best_depth_update->bid5_price / decimal,
                   (uint32_t)best_depth_update->bid5_volumn, 
                   (uint32_t)best_depth_update->bid5_qty,

                   (float)best_depth_update->bid4_price / decimal,
                   (uint32_t)best_depth_update->bid4_volumn,
                   (uint32_t)best_depth_update->bid4_qty,


                   (float)best_depth_update->bid3_price / decimal,
                   (uint32_t)best_depth_update->bid3_volumn,
                   (uint32_t)best_depth_update->bid3_qty,


                   (float)best_depth_update->bid2_price / decimal,
                   (uint32_t)best_depth_update->bid2_volumn,
                   (uint32_t)best_depth_update->bid2_qty,


                   // ntohl((uint32_t)best_depth_update->bid1) & 0x03ffffff, // price
                   // ntohl(best_depth_update->bid1 >> 32) & 0x00000fff, // qty
                   // (ntohl(best_depth_update->bid1 >> 32) & 0xfffff000) >> 12, // volumn
                   (float)best_depth_update->bid1_price / decimal,
                   (uint32_t)best_depth_update->bid1_volumn,
                   (uint32_t)best_depth_update->bid1_qty,

                   (float)best_depth_update->ask1_price / decimal,
                   (uint32_t)best_depth_update->ask1_volumn,
                   (uint32_t)best_depth_update->ask1_qty,

                   (float)best_depth_update->ask2_price / decimal,
                   (uint32_t)best_depth_update->ask2_volumn,
                   (uint32_t)best_depth_update->ask2_qty,

                   (float)best_depth_update->ask3_price / decimal,
                   (uint32_t)best_depth_update->ask3_volumn,
                   (uint32_t)best_depth_update->ask3_qty,

                   (float)best_depth_update->ask4_price / decimal,
                   (uint32_t)best_depth_update->ask4_volumn,
                   (uint32_t)best_depth_update->ask4_qty,


                   (float)best_depth_update->ask5_price / decimal,
                   (uint32_t)best_depth_update->ask5_volumn,
                   (uint32_t)best_depth_update->ask5_qty

            );
#endif
        }
    }
    // close(sockfd);
    return 0;
}
